package cn.lg.soar.mvc.handler;

import cn.lg.soar.common.constant.SystemConst;
import cn.lg.soar.common.exceptions.AuthenticationException;
import cn.lg.soar.common.exceptions.BaseBException;
import cn.lg.soar.common.exceptions.PermissionException;
import cn.lg.soar.common.model.HttpResult;
import cn.lg.soar.common.util.current.ICurrentUser;
import cn.lg.soar.common.util.current.ThreadLocalHolder;
import cn.lg.soar.core.dto.PermitLevel;
import cn.lg.soar.core.manager.BaseAuthenticationManager;
import cn.lg.soar.core.manager.IAccessTokenValidator;
import cn.lg.soar.core.manager.PermitLevelManager;
import cn.lg.soar.mvc.util.ResponseUtils;
import cn.lg.soar.mvc.util.ServletUtils;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;

import java.io.IOException;
import java.util.function.Function;

/**
 * 权限过滤器
 * @author luguoxiang
 * @date 2022/8/25
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class AuthFilter implements Filter {
    // 权限级别管理器
    private final PermitLevelManager permitLevelManager;
    // token管理器
    private final IAccessTokenValidator accessTokenValidator;
    // 权限验证管理器
    private final BaseAuthenticationManager<Long> authenticationManager;
    // 是否是超级管理员
    private final Function<Long, Boolean> isSuperAdministrator;

    public AuthFilter(PermitLevelManager permitLevelManager, IAccessTokenValidator accessTokenValidator, BaseAuthenticationManager<Long> authenticationManager, Function<Long, Boolean> isSuperAdministrator) {
        this.permitLevelManager = permitLevelManager;
        this.accessTokenValidator = accessTokenValidator;
        this.authenticationManager = authenticationManager;
        this.isSuperAdministrator = isSuperAdministrator;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String permit = request.getMethod().toUpperCase() + request.getServletPath();
        // 获取权限级别
        PermitLevel permitLevel = permitLevelManager.match(permit);
        if (permitLevel == PermitLevel.anon) {
            // 匿名接口直接访问
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        if (permitLevel == PermitLevel.closed) {
            // 关闭的接口不可访问
            response.setStatus(HttpStatus.NOT_FOUND.value());
            ResponseUtils.responseBody(response, HttpResult.fail(new BaseBException(407, "该接口已关闭")));
            return;
        }

        // 验证token
        ICurrentUser currentUser;
        String token = ServletUtils.getHeaderOrParameter(request, SystemConst.TOKEN_NAME);
        if (token == null) {
            currentUser = null;
        } else {
            currentUser = accessTokenValidator.verify(token);
            // 保存用户信息
            ThreadLocalHolder.setCurrentUser(currentUser);
        }

        if (permitLevel == PermitLevel.identifiable) {
            // 可识别的接口直接访问
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        } else if (currentUser == null) {
            // token无效，需先登录
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            ResponseUtils.responseBody(response, HttpResult.fail(new AuthenticationException()));
            return;
        }

        if (permitLevel == PermitLevel.authenticated) {
            // 登录即可访问
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        if (permitLevel == PermitLevel.authorized) {
            // 需要指定权限
            if (authenticationManager.hasPermit(currentUser.getId(), permit)) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
        } else {
            // 需要指定用户类型
            Integer userType = currentUser.getUserType();
            if (permitLevel.getUserTypes().contains(userType)) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
        }

        // 是否是超级管理员
        if (Boolean.TRUE.equals(isSuperAdministrator.apply(currentUser.getId()))) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        // 无权限
        response.setStatus(HttpStatus.FORBIDDEN.value());
        ResponseUtils.responseBody(response, HttpResult.fail(new PermissionException()));
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
}
